﻿namespace ConcurrentBoo.Executors

import System
import System.Threading
import ConcurrentBoo

class ThreadedExecutor(IExecutor):
"""
Base class for executors that dispatch actions to
a single dedicated thread.
"""
	private static final EndThread = object()
	
	final _channel as IChannel

	_thread as Thread
	
	def constructor():
		_channel = Channel()
		
	def constructor(channel as IChannel):
		_channel = channel
	
	public event Error as ErrorEvent
	
	def Execute([required] action as ConcurrentBoo.Action):
		lock self:
			EnsureThreadStarted_()
			if _thread is Thread.CurrentThread:
				ProcessAction(action)
				return
			
		_channel.Put(action)
	
	def Shutdown():
		Shutdown(Timeout.Infinite)
		
	def Shutdown(millisecondsTimeout as int):
		lock self:
			thread = _thread
		if thread is null: return
		assert thread is not Thread.CurrentThread
		_channel.Put(EndThread)
		return _thread.Join(millisecondsTimeout)
		
	[lock]
	private def ClearThread():
		_thread = null
		Monitor.PulseAll(self)
	
	[lock]
	private def EnsureThreadStarted():
		EnsureThreadStarted_()
		
	private def EnsureThreadStarted_():
		if _thread is not null: return
		_thread = CreateThread()
		_thread.Start()
		
	protected virtual def CreateThread():
		return Thread(EntryPoint, IsBackground: true)
		
	protected def EntryPoint():
		try:
			ExecutionLoop()
		ensure:
			ClearThread()

	protected def ProcessNextMessage() as bool:
		return ProcessMessage(_channel.Take())
		
	protected def ProcessMessage(message) as bool:
		if message is EndThread:
			return false		
		return ProcessAction(message)
		
	protected def ProcessAction(action as ConcurrentBoo.Action):
		try:
			action()
		except x:
			OnError(x)
		return true
			
	protected def OnError(x as Exception):
		try:
			Error(self, ErrorEventArgs(x))
		except x:
			pass

	protected abstract def ExecutionLoop():
		pass
		
